/*
 * Copyright 2007 Jeffrey Palm
 */

import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import java.util.*;
import java.util.List;
import javax.swing.*;

/**
 * The base class for readers that have the ontology:
 *   
 *    RSS      ::= Category* 
 *    Category ::= Article*
 */
abstract class AbstractNewsReader extends AbstractFinderIPod {

  /**
   * @return a list of {@link #Link} representing the categories
   */
  abstract Collection findCategories() throws IOException;
  
  /**
   * @return the long title for this finder
   */
  abstract String title();

  /**
   * @return a link to the main image to display at the top of the finder window
   */
  abstract String imageURL();

  /**
   * @return all the links from a category page
   */
  abstract Collection findArticleLinks(Link category) throws IOException;

  /**
   * @return a new Article for the parent and child Links
   */
  abstract Article createArticle(Link parent, Link l) throws Exception;

  protected final void findRest(final IPod ipod, Progress p) throws Exception {

    // Find the links
    final Vector links = new Vector(findCategories());

    // Sort by name
    Collections.sort(links,new Comparator() {
        public int compare(Object o1, Object o2) {
          return ((Link)o1).name.compareTo(((Link)o2).name);
        }
        public boolean equals(Object o) {
          return o == this;
        }
      });

    // Show the main panel
    JFrame f = new JFrame(title());
    f.getContentPane().setLayout(new BorderLayout());
    final MainPanel mp = new MainPanel(ipod,links,p);
    f.getContentPane().add(mp);
    Util.show(f);
  }

  protected final static class Link {
    final String name;
    final String link;
    Link(String name, String link) {
      this.name = name;
      this.link = link;
    }
    public String toString() {return name;}
  }

  private class MainPanel extends JPanel {

    private final ProgressPanel progress = new ProgressPanel();
    public Progress getProgress() {
      return progress;
    }

    private void selectAll(JList lst, List links) {
      int[] sel = new int[links.size()];
      for (int i=0; i<sel.length; i++) sel[i] = i;
      lst.setSelectedIndices(sel);
    }

    MainPanel(final IPod ipod, final Vector links, final Progress p) {
      setLayout(new BorderLayout());

      // center
      final JList lst = new JList(links);
      selectAll(lst,links);
      add(new JScrollPane(lst),BorderLayout.CENTER);
      
      // top
      JPanel top = Util.yp();
      try {
        String imageURL = imageURL();
        if (imageURL != null) {
          JLabel l = new JLabel(new ImageIcon(new URL(imageURL)));
          top.add(l);
        }
      } catch (Exception e) {
        top.add(new JLabel(title()));
        e.printStackTrace();
      }
      add(top,BorderLayout.NORTH);

      // bottom
      JPanel realBottom = Util.yp();
      JPanel bottom = Util.xp();
      realBottom.add(progress);
      bottom.add(new JButton(new AbstractAction("Select all") {
          public void actionPerformed(ActionEvent e) {
            selectAll(lst,links);
          }
        }));
      bottom.add(new JButton(new AbstractAction("Select none") {
          public void actionPerformed(ActionEvent e) {
            int[] sel = new int[0];
            lst.setSelectedIndices(sel);
          }
        }));
      bottom.add(new JButton(new AbstractAction("Download") {
          public void actionPerformed(ActionEvent e) {
            Object[] sel = lst.getSelectedValues();
            if (sel == null || sel.length<1) {
              Util.showError("You must select at least one secion");
            } else {
              download(MainPanel.this,ipod,sel,p);
            }
          }
        }));
      realBottom.add(bottom);
      add(realBottom,BorderLayout.SOUTH);
    }
  }

  protected final String prettyLink(Link l) {
    String link = l.link;
    int iq = link.lastIndexOf("?");
    if (iq != -1) link = link.substring(0,iq);
    return link;
  }

  private void download(final MainPanel mp, IPod ipod, Object[] sel, final Progress p) {
    
    p.setMax(sel.length);

    File notes = null;
    while (notes == null || !notes.exists()) {
      notes = ipod.getNotes();
    }
    File base = Util.newDir(notes,name());
    if (base.exists()) base.delete();
    
    int count = 0;
    for (int i=0; i<sel.length; i++) {
      final Link l = (Link)sel[i];
      new Thread(new Runnable() {
          public void run() {
            p.update("Downloading " + l.name + " Section",1);
            mp.repaint();
          }}).start();
      
      // create the outdir and delete all the files
      File outDir = Util.newDir(base,l.name);
      File[] fs = outDir.listFiles();
      for (int j=0; j<fs.length; j++) {
        if (fs[j] == null) continue;
        try {fs[j].delete();} catch (Exception e) {e.printStackTrace();}
      }
      
      List links = null;
      try {
        links = new ArrayList(findArticleLinks(l));
      } catch (Exception e) {Util.handle(this,e);}
      if (links == null) continue;
      for (Iterator it = links.iterator(); it.hasNext();) {
        Link sl = (Link)it.next();
        try {
          p.update("Downloading article " + l.name + " :: " + sl.name,0);
          mp.repaint();
          Article a = createArticle(l,sl);
          if (a.author() == null) continue;
          File outFile = new File(outDir,a.title());
          PrintStream out = new PrintStream(new FileOutputStream(outFile));
          out.println(a.format());
          out.close();
          count++;
        } catch (Exception ee) {ee.printStackTrace();}
      }
    }

    String msg = "Downloaded " + count + " article";
    if (count != 1) msg += "s";
    Util.showMsg(msg);
  }

  protected final static class Article {
    
    private final Link link;
    private String author;
    private String date;
    private final StringBuffer contents = new StringBuffer();

    Article(Link link) {
      this.link = link;
    }

    String date() {
      return date;
    }
    void setDate(String date) {
      this.date = date;
    }
    String link() {
      return link.link;
    }
    String title() {
      return link.name;
    }
    String author() {
      return author;
    }
    void setAuthor(String author) {
      this.author = author;
    }
    String contents() {
      return contents.toString();
    }
    void addContent(String line) {
      contents.append(line);
    }

    public String format() {
      StringBuffer res = new StringBuffer();
      res.append(title()).append("\n");
      res.append("By ").append(author()).append("\n");
      res.append("================\n\n");
      res.append(contents());
      return res.toString();
    }
  }

  protected final String innerHTML(String line, int startIndex) {
    if (startIndex == -1) return null;
    int igt = line.indexOf(">",startIndex);
    if (igt == -1) return null;
    int ilt = line.indexOf("<",igt);
    if (ilt == -1) return null;
    String name = line.substring(igt+1,ilt).trim();
    return name;
  }

}